package com.cwd.arm.application.service.read;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.cwd.arm.application.dto.ConfirmIncomeDto;
import com.cwd.arm.application.dto.ReceiveNodeDto;
import com.cwd.arm.application.service.read.facade.ReceiveNodeReadService;
import com.cwd.arm.common.util.BigDecimalUtil;
import com.cwd.arm.common.util.DateUtil;
import com.cwd.arm.infrastructure.dao.ProjectDao;
import com.cwd.arm.infrastructure.dao.ReceiveNodeDao;
import com.cwd.arm.infrastructure.po.ProjectPo;
import com.cwd.arm.infrastructure.po.ReceiveNodePo;
import com.cwd.arm.infrastructure.query.ReceiveNodeDaoQuery;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Repository;

import java.math.BigDecimal;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Description:收款节点
 * Created on 2021年11月16日
 *
 * @author yan
 */
@Repository
@Primary
public class ReceiveNodeReadServiceImpl implements ReceiveNodeReadService {

    @Autowired
    private ReceiveNodeDao receiveNodeDao;

    @Autowired
    private ProjectDao projectDao;

    @Override
    public ReceiveNodeDto selectById(Long id) {
        return convertToDto(receiveNodeDao.getById(id));
    }

    @Override
    public List<ReceiveNodeDto> selectByProjectId(Long projectId) {
        ReceiveNodeDaoQuery daoQuery = new ReceiveNodeDaoQuery();
        daoQuery.setProjectId(projectId);
        return selectByQuery(daoQuery);
    }

    @Override
    public List<ReceiveNodeDto> selectByQuery(ReceiveNodeDaoQuery daoQuery) {
        List<ReceiveNodePo> poList = receiveNodeDao.selectByQuery(daoQuery);
        poList = poList.stream().sorted(Comparator.comparing(ReceiveNodePo::getEndDate)).collect(Collectors.toList());
        ProjectPo projectPo = projectDao.getById(daoQuery.getProjectId());
        BigDecimal contractAmount = BigDecimalUtil.hasRecord(projectPo.getCloseAmount())? projectPo.getCloseAmount(): projectPo.getContractAmount();
        List<ReceiveNodeDto> receiveNodeDtoList = convertToDtoList(poList);
        BigDecimal receivableAmount = BigDecimal.ZERO;
        BigDecimal closeAmount = BigDecimal.ZERO;
        for(ReceiveNodeDto receiveNodeDto : receiveNodeDtoList){
            receivableAmount = BigDecimalUtil.add(receiveNodeDto.getReceivableAmount(),receivableAmount);
            receiveNodeDto.setCompletionRate(BigDecimalUtil.div2(receivableAmount,contractAmount));
            closeAmount = BigDecimalUtil.add(receiveNodeDto.getCloseAmount(),closeAmount);
            receiveNodeDto.setActualRate(BigDecimalUtil.div2(closeAmount,contractAmount));
        }
        return receiveNodeDtoList;
    }


    @Override
    public BigDecimal getRate(Long projectId, Long nodeId, BigDecimal amount,String date) throws Exception{
        BigDecimal receivableAmount = amount;
        Date endDate = DateUtil.strToDate(date);

        //对修改的处理
        if (nodeId != null && StringUtils.isNotEmpty(date)) {//对修改的处理,时间不传时也当新增,且默认为最晚的时间
            ReceiveNodePo oldReceiveNodePo = receiveNodeDao.getById(nodeId);
            if (!DateUtil.isBeforeDate(endDate, oldReceiveNodePo.getEndDate())
                    || DateUtil.isTheSameDate(endDate,oldReceiveNodePo.getEndDate())) {//如果现在的日期在之前日期之后需要减去之前日期
                receivableAmount = BigDecimalUtil.sub(amount, oldReceiveNodePo.getReceivableAmount());
            }
        }
        //已有记录要加上已有记录
        List<ReceiveNodePo> receiveNodePoList = getOldNodeList(projectId, endDate);
        if (CollectionUtils.isNotEmpty(receiveNodePoList)) {
            BigDecimal oldAmountTotal = receiveNodePoList.stream().map(ReceiveNodePo::getReceivableAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            receivableAmount = BigDecimalUtil.add(receivableAmount, oldAmountTotal);
        }

        ProjectPo projectPo = projectDao.getById(projectId);
        BigDecimal contractAmount = BigDecimalUtil.hasRecord(projectPo.getCloseAmount())? projectPo.getCloseAmount(): projectPo.getContractAmount();
        return BigDecimalUtil.div2(receivableAmount, contractAmount);
    }

    @Override
    public BigDecimal getAmount(Long projectId, Long nodeId, BigDecimal rate,String date) throws Exception{
        BigDecimal receivableAmount = BigDecimal.ZERO;
        Date endDate = DateUtil.strToDate(date);

        if (nodeId != null && StringUtils.isNotEmpty(date)) {//对修改的处理,时间不传时也当新增,且默认为最晚的时间
            ReceiveNodePo oldReceiveNodePo = receiveNodeDao.getById(nodeId);
            if (!DateUtil.isBeforeDate(endDate, oldReceiveNodePo.getEndDate())
                    || DateUtil.isTheSameDate(endDate,oldReceiveNodePo.getEndDate())) {
                receivableAmount = BigDecimalUtil.sub(receivableAmount, oldReceiveNodePo.getReceivableAmount());
            }
        }
        //已有记录要加上已有记录
        List<ReceiveNodePo> receiveNodePoList = getOldNodeList(projectId, endDate);
        if (CollectionUtils.isNotEmpty(receiveNodePoList)) {
            BigDecimal oldAmountTotal = receiveNodePoList.stream().map(ReceiveNodePo::getReceivableAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            receivableAmount = BigDecimalUtil.add(receivableAmount, oldAmountTotal);
        }
        ProjectPo projectPo = projectDao.getById(projectId);
        BigDecimal contractAmount = BigDecimalUtil.hasRecord(projectPo.getCloseAmount())? projectPo.getCloseAmount(): projectPo.getContractAmount();
        BigDecimal amount = contractAmount.multiply(rate);
        return amount.subtract(receivableAmount);
    }

    private List<ReceiveNodePo> getOldNodeList(Long projectId, Date date){
        ReceiveNodeDaoQuery daoQuery = new ReceiveNodeDaoQuery();
        daoQuery.setProjectId(projectId);
        daoQuery.setLeEndDate(date);
        return receiveNodeDao.selectByQuery(daoQuery);
    }

    private ReceiveNodeDto convertToDto(ReceiveNodePo po) {
        ReceiveNodeDto dto = new ReceiveNodeDto();
        BeanUtils.copyProperties(po, dto);
        BigDecimal unReceivedAmount = po.getReceivableAmount().subtract(po.getCloseAmount());
        dto.setUnReceivedAmount(unReceivedAmount);
        return dto;
    }

    private List<ReceiveNodeDto> convertToDtoList(List<ReceiveNodePo> poList) {
        return poList.stream().map(po -> convertToDto(po)).collect(Collectors.toList());
    }

}
